using System;
using System.Collections.Generic;
using System.Text;

using XNAF = Microsoft.Xna.Framework;

using XGAE.Framework;
using XGAE.Framework.Extensions;

namespace XGAE.Framework.Body.Physics
{
    /// <summary>
    /// Allow the other sensor and effector modules to convert relative commands into absolute
    /// world coordinates.
    /// </summary>
    public interface IConversion
    {
        /// <summary>
        /// Provide the relative angles to restore the horizontal view.
        /// </summary>
        /// <param name="relative"></param>
        /// <param name="global"></param>
        void ToGlobal(XNAF.Vector3 relative, ref XNAF.Vector3 global);

        /// <summary>
        /// Provide the relative angles to restore the horizontal view.
        /// </summary>
        /// <param name="global"></param>
        /// <param name="relative"></param>
        void ToRelative(XNAF.Vector3 global, ref XNAF.Vector3 relative);
    }

    /// <summary>
    /// Sensor queries allowing the animat to perceive relative movement.
    /// </summary>
    public interface IRelative
    {
        /// <summary>
        /// Odometric query to check how far we have gone relatively to the last position.
        /// </summary>
        /// <param name="movement"></param>
        void GetMovement(out XNAF.Vector3 movement);

        /// <summary>
        /// Assertain how we've rotated from the previous position.
        /// </summary>
        /// <returns></returns>
        Angles GetOrientation();

        /// <summary>
        /// The relative angle to zero pitch.
        /// </summary>
        /// <returns></returns>
        float GetBalance();
    }

    /// <summary>
    /// Collection of sensor queries that provide a notion of an animat's physical state.
    /// </summary>
    public interface IState
    {
        /// <summary>
        /// Did a collision with a static or dynamic obstacle occur?
        /// </summary>
        /// <param name="normal"></param>
        /// <returns></returns>
        bool IsCollision(XNAF.Vector3 normal);

        /// <summary>
        /// Check the presence of a platform beneath us.
        /// </summary>
        /// <returns></returns>
        bool IsPlatform();

        /// <summary>
        /// Retrieve an entity for the platform below.
        /// </summary>
        /// <returns></returns>
        Entity GetPlatform();

        /// <summary>
        /// Is the agent currently holding onto a ladder?
        /// </summary>
        /// <returns></returns>
        bool IsLadder();

        /// <summary>
        /// Are we in any kind of liquid?
        /// </summary>
        /// <returns></returns>
        bool IsWater();

        /// <summary>
        /// Check if the animat is touching the floor or not.
        /// </summary>
        /// <returns></returns>
        bool IsAir();
    }

    /// <summary>
    /// Asynchronous interuption of control when a collision occurs with an obstacle.
    /// </summary>
    public class CollisionMessage : Message
    {
        private XNAF.Vector3 _normal; // Normal of the obstacle in relative space.

        public XNAF.Vector3 Normal
        {
            get { return this._normal; }
        }

        public CollisionMessage()
        :   base("Collision")
        {}

        public CollisionMessage(XNAF.Vector3 normal)
        :   base("Collision")
        {
            this._normal = normal;
        }
    }
}